<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/%E6%AD%A6%E6%B1%8932x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/%E6%AD%A6%E6%B1%8916x16.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib1/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="/lib1/pace/pace-theme-center-simple.min.css">
  <script src="/lib1/pace/pace.min.js"></script>

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"example.com","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="前言最近在参加秋招，遇到了各式的手撕代码的面试题，有当场写出的，有以前写过现在死活不知道怎么办的，还有写出基本功能，但对于细节上的优化相当不足，不能体现自己编码的严谨性的，因此，在这里总结了下手写JS问题的博客。 1、promise相关promise相关的手写问题主要有两个吧，一个是自己实现一个简单的promise.all的方法，能够让传入的promise同时并行执行，直到所有的promise均执">
<meta property="og:type" content="article">
<meta property="og:title" content="JS手写问题">
<meta property="og:url" content="http://example.com/2021/08/15/%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93/JS%E6%89%8B%E5%86%99%E9%97%AE%E9%A2%98/index.html">
<meta property="og:site_name" content="Technological Blog">
<meta property="og:description" content="前言最近在参加秋招，遇到了各式的手撕代码的面试题，有当场写出的，有以前写过现在死活不知道怎么办的，还有写出基本功能，但对于细节上的优化相当不足，不能体现自己编码的严谨性的，因此，在这里总结了下手写JS问题的博客。 1、promise相关promise相关的手写问题主要有两个吧，一个是自己实现一个简单的promise.all的方法，能够让传入的promise同时并行执行，直到所有的promise均执">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-08-15T13:28:16.000Z">
<meta property="article:modified_time" content="2021-11-03T08:24:34.493Z">
<meta property="article:author" content="Li Yudong">
<meta property="article:tag" content="面试总结">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="http://example.com/2021/08/15/%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93/JS%E6%89%8B%E5%86%99%E9%97%AE%E9%A2%98/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>JS手写问题 | Technological Blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Technological Blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">IT小白的成长之旅</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="tags fa-fw"></i>标签<span class="badge">18</span></a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="th fa-fw"></i>分类<span class="badge">14</span></a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="archive fa-fw"></i>归档<span class="badge">95</span></a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <a href="https://github.com/tiarmor1" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/08/15/%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93/JS%E6%89%8B%E5%86%99%E9%97%AE%E9%A2%98/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/author.jpg">
      <meta itemprop="name" content="Li Yudong">
      <meta itemprop="description" content="">
    </span>
    
    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Technological Blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          JS手写问题
        </h1>
    
        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
    
              <time title="创建时间：2021-08-15 21:28:16" itemprop="dateCreated datePublished" datetime="2021-08-15T21:28:16+08:00">2021-08-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-11-03 16:24:34" itemprop="dateModified" datetime="2021-11-03T16:24:34+08:00">2021-11-03</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93/" itemprop="url" rel="index"><span itemprop="name">面试总结</span></a>
                </span>
            </span>
    
          
    
        </div>
      </header>
    
    
    
    
    <div class="post-body" itemprop="articleBody">
    
      
        <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近在参加秋招，遇到了各式的手撕代码的面试题，有当场写出的，有以前写过现在死活不知道怎么办的，还有写出基本功能，但对于细节上的优化相当不足，不能体现自己编码的严谨性的，因此，在这里总结了下手写JS问题的博客。</p>
<h2 id="1、promise相关"><a href="#1、promise相关" class="headerlink" title="1、promise相关"></a>1、promise相关</h2><p><strong>promise相关的手写问题主要有两个吧，一个是自己实现一个简单的promise.all的方法，能够让传入的promise同时并行执行，直到所有的promise均执行成功后再执行回调函数。一个是promise的串行执行，让promise由并行转为依次串行执行</strong></p>
<p>知识点扩充：基本类型保存再栈中，值不可变、但可以重新赋值，是值之间的比较。引用类型保存再堆中，值可变，是引用的比较。这里往往会引出深浅拷贝的问题，因为不用拷贝来进行复制对象时，由于传递的是值的引用，因此指向的是同一对象。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">实现一个promiseAll([ PromiseA, PromiseB, ])</span></span><br><span class="line"><span class="comment">使PromiseX能并行执行，并返回Promise？</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">const</span> promiseAll = <span class="function"><span class="keyword">function</span> (<span class="params">arr</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (arr.length === <span class="number">0</span>) &#123;</span><br><span class="line">        resolve([]);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> result = []</span><br><span class="line">        <span class="keyword">let</span> num = <span class="number">0</span>; </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.length; i++) &#123;</span><br><span class="line">          arr[i].then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            num++;</span><br><span class="line">            result[i] = res;</span><br><span class="line">            <span class="keyword">if</span> (num == arr.length) resolve(result);</span><br><span class="line">          &#125;, reject);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> pro1 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">res,rej</span>) =&gt;</span> &#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      res(<span class="string">'1'</span>)</span><br><span class="line">    &#125;,<span class="number">1000</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">const</span> pro2 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">res,rej</span>) =&gt;</span> &#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      res(<span class="string">'2'</span>)</span><br><span class="line">    &#125;,<span class="number">2000</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">const</span> pro3 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">res,rej</span>) =&gt;</span> &#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      res(<span class="string">'5'</span>)</span><br><span class="line">    &#125;,<span class="number">5000</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">  </span><br><span class="line">  promiseAll([pro1, pro2, pro3]).then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(res);</span><br><span class="line">  &#125;);</span><br><span class="line">  </span><br><span class="line">  </span><br><span class="line">  <span class="comment">/*</span></span><br><span class="line"><span class="comment">  实现Promise.run([returnPromiseA, returnPromiseB, returnPromiseC, ])，</span></span><br><span class="line"><span class="comment">  使得returnPromiseX方法返回的Promise能够串行执行，返回Promise？</span></span><br><span class="line"><span class="comment">  </span></span><br><span class="line"><span class="comment">  在promise中，如果then方法返回的是一个promise对象，</span></span><br><span class="line"><span class="comment">  那么执行下一个then的时候必定是在上一个人then执行完之后执行</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="keyword">const</span> promiseRun = <span class="function"><span class="keyword">function</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> ans = [];</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">        arr.reduce(<span class="function">(<span class="params">pre, cur</span>) =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">return</span> pre.then(cur);</span><br><span class="line">        &#125;,<span class="built_in">Promise</span>.resolve());</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">returnPromiseA</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve</span>)=&gt;</span>&#123;</span><br><span class="line">      setTimeout(<span class="function"><span class="params">()</span>=&gt;</span>&#123; resolve(<span class="string">"1"</span>) &#125;, <span class="number">1000</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">returnPromiseB</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve</span>)=&gt;</span>&#123;</span><br><span class="line">      setTimeout(<span class="function"><span class="params">()</span>=&gt;</span>&#123; resolve(<span class="string">"2"</span>) &#125;, <span class="number">2000</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">returnPromiseC</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve</span>)=&gt;</span>&#123;</span><br><span class="line">      setTimeout(<span class="function"><span class="params">()</span>=&gt;</span>&#123; resolve(<span class="string">"5"</span>) &#125;, <span class="number">5000</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  promiseRun([returnPromiseA, returnPromiseB, returnPromiseC]).then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(res);</span><br><span class="line">  &#125;);</span><br></pre></td></tr></table></figure>



<h2 id="2、深拷贝、浅拷贝"><a href="#2、深拷贝、浅拷贝" class="headerlink" title="2、深拷贝、浅拷贝"></a>2、深拷贝、浅拷贝</h2><p><strong>深浅拷贝都是对引用类型的复制。浅拷贝只拷贝一层，对于深层次的对象级别，仍然会拷贝引用；而深拷贝能够拷贝多层次的嵌套对象。</strong></p>
<p>1、浅拷贝</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">simpleCopy</span> (<span class="params">obj1</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> obj2 = <span class="built_in">Array</span>.isArray(obj1) ? [] : &#123;&#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">in</span> obj1) &#123;</span><br><span class="line">        obj2[i] = obj1[i]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> obj2</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>2、初始版本</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">'object'</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> cloneTarget = &#123;&#125;;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">            cloneTarget[key] = clone(target[key]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>3、考虑数组的情况</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">'object'</span>) &#123;</span><br><span class="line">        <span class="comment">//只需要在初始化暂存变量值时，用Array.isArray来判断为[]，还是&#123;&#125;即可。</span></span><br><span class="line">        <span class="keyword">let</span> cloneTarget = <span class="built_in">Array</span>.isArray(target) ? [] : &#123;&#125;;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">            cloneTarget[key] = clone(target[key]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>4、循环引用问题</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">上面的代码看似能实现功能，但是当对象存在循环引用问题时，则会导致递归出现死循环。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">const</span> target = &#123;</span><br><span class="line">    field1: <span class="number">1</span>,</span><br><span class="line">    field2: <span class="literal">undefined</span>,</span><br><span class="line">    field3: &#123;</span><br><span class="line">        child: <span class="string">'child'</span></span><br><span class="line">    &#125;,</span><br><span class="line">    field4: [<span class="number">2</span>, <span class="number">4</span>, <span class="number">8</span>]</span><br><span class="line">&#125;;</span><br><span class="line">target.target = target;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">解决循环引用问题，我们可以额外开辟一个存储空间，来存储当前对象和拷贝对象的对应关系，当需要拷贝当前对象时，先去存储空间中找，有没有拷贝过这个对象，如果有的话直接返回，如果没有的话继续拷贝，这样就巧妙化解的循环引用的问题。</span></span><br><span class="line"><span class="comment">这里我们使用Map这种数据结构</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target, map = new Map(</span>)) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">'object'</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> cloneTarget =  <span class="built_in">Array</span>.isArray(target) ? [] : &#123;&#125;;</span><br><span class="line">        <span class="keyword">if</span> (map.has(target)) &#123;</span><br><span class="line">            <span class="keyword">return</span> map.get(target);</span><br><span class="line">        &#125;</span><br><span class="line">        map.set(target, cloneTarget);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">            cloneTarget[key] = clone(target[key], map);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>5、其他数据类型处理</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//在判断引用类型时，考虑function与null这种特殊情况</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isObject</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> type = <span class="keyword">typeof</span> target;</span><br><span class="line">    <span class="keyword">return</span> target !== <span class="literal">null</span> &amp;&amp; (type === <span class="string">'object'</span> || type === <span class="string">'function'</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//对于引用类型，利用Object.toString()来获取准确引用类型</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getType</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Object</span>.prototype.toString.call(target);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*对于之前说的object、array以及Map、set都属于可继续遍历的类型</span></span><br><span class="line"><span class="comment">我们通过拿到constructor的方式来通用地获取</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getInit</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> Ctor = target.constructor;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Ctor();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target, map = new WeakMap(</span>)) </span>&#123;</span><br><span class="line">    <span class="comment">// 克隆原始类型</span></span><br><span class="line">    <span class="keyword">if</span> (!isObject(target)) &#123;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 初始化</span></span><br><span class="line">    <span class="keyword">const</span> type = getType(target);</span><br><span class="line">    <span class="keyword">let</span> cloneTarget;</span><br><span class="line">    <span class="keyword">if</span> (deepTag.includes(type)) &#123;</span><br><span class="line">        cloneTarget = getInit(target, type);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 防止循环引用</span></span><br><span class="line">    <span class="keyword">if</span> (map.get(target)) &#123;</span><br><span class="line">        <span class="keyword">return</span> map.get(target);</span><br><span class="line">    &#125;</span><br><span class="line">    map.set(target, cloneTarget);</span><br><span class="line">    <span class="comment">// 克隆set</span></span><br><span class="line">    <span class="keyword">if</span> (type === setTag) &#123;</span><br><span class="line">        target.forEach(<span class="function"><span class="params">value</span> =&gt;</span> &#123;</span><br><span class="line">            cloneTarget.add(clone(value,map));</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 克隆map</span></span><br><span class="line">    <span class="keyword">if</span> (type === mapTag) &#123;</span><br><span class="line">        target.forEach(<span class="function">(<span class="params">value, key</span>) =&gt;</span> &#123;</span><br><span class="line">            cloneTarget.set(key, clone(value,map));</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 克隆对象和数组</span></span><br><span class="line">    <span class="keyword">const</span> keys = type === arrayTag ? <span class="literal">undefined</span> : <span class="built_in">Object</span>.keys(target);</span><br><span class="line">    forEach(keys || target, (value, key) =&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (keys) &#123;</span><br><span class="line">            key = value;</span><br><span class="line">        &#125;</span><br><span class="line">        cloneTarget[key] = clone(target[key], map);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> cloneTarget;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="3、判断数据类型"><a href="#3、判断数据类型" class="headerlink" title="3、判断数据类型"></a>3、判断数据类型</h2><p><strong>一般使用typeof、instanceof，或者使用object.tostring方法，从而判断数据类型。</strong></p>
<p>typeof 是一个操作符，其右侧跟一个一元表达式，并返回这个表达式的数据类型。对于null、array不能判断。</p>
<p>instanceof 可以正确判断对象的数据类型，用来判断 A 是否为 B 的实例;内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。</p>
<p>toString()：是 Object 的原型方法，调用该方法，默认返回当前对象的 [[Class]] 。</p>
<p>这是一个内部属性，其格式为 [object xxx] ，其中 xxx 就是对象的类型。对于 Object 对象，直接调用 toString() 就能返回 [object Object] 。而对于其他对象，则需要通过 call / apply 来调用才能返回正确的类型信息。很多时候</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call(<span class="number">1</span>);  <span class="comment">//'[object Number]'</span></span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call(<span class="string">'1'</span>); <span class="comment">//'[object String]'</span></span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call(<span class="literal">NaN</span>); <span class="comment">//'[object Number]'</span></span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call(foo);  <span class="comment">//'[object Function]'</span></span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call([<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]); <span class="comment">//'[object Array]'</span></span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call(<span class="literal">undefined</span>); <span class="comment">//'[object Undefined]'</span></span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call(<span class="literal">null</span>); <span class="comment">//'[object Null]'</span></span><br><span class="line"><span class="built_in">Object</span>.prototype.toString.call(<span class="literal">true</span>); <span class="comment">//'[object Boolean]'</span></span><br></pre></td></tr></table></figure>

<h2 id="4、数组常见API"><a href="#4、数组常见API" class="headerlink" title="4、数组常见API"></a>4、数组常见API</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> arr3 = arr1.concat(arr2);<span class="comment">//合并且返回副本</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> bar = [<span class="string">"a"</span>, <span class="string">"b"</span>, <span class="string">"c"</span>];</span><br><span class="line"><span class="built_in">Array</span>.from(bar);<span class="comment">//from()方法返回一个新的数组迭代器对象，该对象包含数组中每个索引的键/值对</span></span><br><span class="line"><span class="keyword">let</span> dp = <span class="built_in">Array</span>.from(<span class="keyword">new</span> <span class="built_in">Array</span>(length1), ()=&gt; &#123;</span><br><span class="line">        <span class="keyword">new</span> <span class="built_in">Array</span>(length2).fill(<span class="number">0</span>);</span><br><span class="line">    &#125;);<span class="comment">//快速定义二维数组</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//find()方法返回满足回调条件的数组中第一个元素的值。否则将返回未定义</span></span><br><span class="line"><span class="comment">//forEach()方法遍历数组,foreach中this指向为undefine</span></span><br><span class="line"><span class="comment">//indexOf()；includes()；均用于查询数组中是否包含某个元素</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//join()将数组中的所有元素(或类似数组的对象)连接到一个字符串中，默认为逗号</span></span><br><span class="line"><span class="keyword">var</span> a = [<span class="string">'Wind'</span>, <span class="string">'Rain'</span>, <span class="string">'Fire'</span>];</span><br><span class="line">a.join();    <span class="comment">// 'Wind,Rain,Fire'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//splice()方法通过删除现有元素和/或添加新元素来更改数组的内容。</span></span><br><span class="line">array.splice(start, deleteCount, item1, item2);</span><br><span class="line">myFish.splice(<span class="number">2</span>, <span class="number">1</span>); <span class="comment">// remove 1 item at 2-index position (that is, "drum")</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//slice()切片</span></span><br><span class="line"><span class="built_in">Array</span>.prototype.slice();<span class="comment">//取出任意元素，参数一：从哪开始；参数二：(可选)结束位置。</span></span><br></pre></td></tr></table></figure>

<h2 id="5、手写bind、call、apply"><a href="#5、手写bind、call、apply" class="headerlink" title="5、手写bind、call、apply"></a>5、手写bind、call、apply</h2><p><strong>相同点：均用于改变函数的上下文，即this指向。</strong></p>
<p>fn.bind： 不会立即调用，而是返回一个绑定后的新函数。fn.call：立即调用，返回函数执行结果，this指向第一个参数，后面可有多个参数，并且这些都是fn函数的参数。fn.apply：立即调用，返回函数的执行结果，this指向第一个参数，第二个参数是个数组，这个数组里内容是fn函数的参数。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//手写call</span></span><br><span class="line"><span class="built_in">Function</span>.prototype.myCall = <span class="function"><span class="keyword">function</span> (<span class="params">thisArg, ...args</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> fn = <span class="built_in">Symbol</span>(<span class="string">"fn"</span>) <span class="comment">// 声明一个独有的Symbol属性, 防止fn覆盖已有属性</span></span><br><span class="line">  thisArg = thisArg || <span class="built_in">window</span> <span class="comment">// 若没有传入this, 默认绑定window对象</span></span><br><span class="line">  thisArg[fn] = <span class="keyword">this</span> <span class="comment">//this指向调用者</span></span><br><span class="line">  <span class="keyword">const</span> result = thisArg[fn](...args) <span class="comment">//执行当前函数</span></span><br><span class="line">  <span class="keyword">delete</span> thisArg[fn]</span><br><span class="line">  <span class="keyword">return</span> result</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 手写apply (args传入一个数组的形式)，原理其实和call差不多，只是入参不一样</span></span><br><span class="line"><span class="built_in">Function</span>.prototype.myApply = <span class="function"><span class="keyword">function</span> (<span class="params">thisArg, args = []</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> fn = <span class="built_in">Symbol</span>(<span class="string">"fn"</span>)</span><br><span class="line">  thisArg = thisArg || <span class="built_in">window</span></span><br><span class="line">  thisArg[fn] = <span class="keyword">this</span></span><br><span class="line">  <span class="comment">//虽然apply()接收的是一个数组，但在调用原函数时，依然要展开参数数组</span></span><br><span class="line">  <span class="comment">//可以对照原生apply()，原函数接收到展开的参数数组</span></span><br><span class="line">  <span class="keyword">const</span> result = thisArg[fn](...args)</span><br><span class="line">  <span class="keyword">delete</span> thisArg[fn]</span><br><span class="line">  <span class="keyword">return</span> result</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//手写bind</span></span><br><span class="line"><span class="built_in">Function</span>.prototype.myBind = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> args = [...arguments]</span><br><span class="line">    <span class="keyword">let</span> ctx = args.length&gt;<span class="number">0</span> ? args.shift() : <span class="built_in">window</span></span><br><span class="line">    <span class="keyword">let</span> s = <span class="built_in">Symbol</span>() <span class="comment">// 生成一个唯一值</span></span><br><span class="line">    <span class="comment">// 在被劫持者对象属性中加入这个属性</span></span><br><span class="line">    ctx[s] = <span class="keyword">this</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">      <span class="keyword">let</span> res = ctx[s](...args) <span class="comment">// 定义了在特定的上下文运行的结果，当执行时就能得到这个特定上下文的结果。</span></span><br><span class="line">      <span class="keyword">delete</span> ctx[s]</span><br><span class="line">      <span class="keyword">return</span> res</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="6、手写new"><a href="#6、手写new" class="headerlink" title="6、手写new"></a>6、手写new</h2><p><strong>1、创建一个新对象；2、将构造函数与新对象在原型链中联系起来，即新对象的proto要指向构造函数的原型对象；3、执行构造函数，并将构造函数的初始属性都挂载在新对象上。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_new</span> (<span class="params">constructor, ...args</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> obj = &#123;&#125;;</span><br><span class="line">    obj._proto_ = <span class="keyword">constructor</span>.prototype;</span><br><span class="line">    let result = <span class="keyword">constructor</span>.call(obj, ...args);</span><br><span class="line">    //在obj中执行构造函数,并将构造函数的属性挂载到对象上；</span><br><span class="line">    return (typeof result === 'object') ? result : obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="7、正确判断this"><a href="#7、正确判断this" class="headerlink" title="7、正确判断this"></a>7、正确判断this</h2><p><strong>核心原理：this的指向在函数定义的时候是确定不了的，只有函数执行的时候才能确定，this不是指向自身！this 就是一个指针，指向调用函数的对象。this最终指向调用它的对象；同样，不管有多少层级的调用，this也只是指向它上一级的对象。</strong></p>
<p>默认绑定：通常情况是函数的调用，此时的this绑定为默认状态，全局执行时指向全局对象window。</p>
<p>隐式绑定：函数的调用是在某个对象上触发的，即调用位置存在上下文对象；典型的形式为XXX.fun()。同样，在这样调用时，由于只有最后一层确定this指向的是什么，因此只绑定最后一层的this。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">隐式绑定的问题，唯有XXX.fn()时才为隐式绑定</span></span><br><span class="line"><span class="comment">除此之外，隐式绑定的丢失可发生在回调函数中</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayHi</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Hello,'</span>, <span class="keyword">this</span>.name);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> person1 = &#123;</span><br><span class="line">    name: <span class="string">'YvetteLau'</span>,</span><br><span class="line">    sayHi: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">'Hello,'</span>,<span class="keyword">this</span>.name);</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> person2 = &#123;</span><br><span class="line">    name: <span class="string">'Christina'</span>,</span><br><span class="line">    sayHi: sayHi</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> name=<span class="string">'Wiliam'</span>;</span><br><span class="line">person1.sayHi();</span><br><span class="line">setTimeout(person2.sayHi,<span class="number">100</span>);</span><br><span class="line">setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    person2.sayHi();</span><br><span class="line">&#125;,<span class="number">200</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">结果为:</span></span><br><span class="line"><span class="comment">Hello, Wiliam</span></span><br><span class="line"><span class="comment">Hello, Wiliam</span></span><br><span class="line"><span class="comment">Hello, Christina</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">第一条输出很容易理解，setTimeout的回调函数中，this使用的是默认绑定，非严格模式下，执行的是全局对象.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">第二条输出是不是有点迷惑了？说好XXX.fun()的时候，fun中的this指向的是XXX呢，为什么这次却不是这样了！Why?</span></span><br><span class="line"><span class="comment">其实这里我们可以这样理解: setTimeout(fn,delay)&#123; fn(); &#125;,相当于是将person2.sayHi赋值给了一个变量，最后执行了变量，这个时候，sayHi中的this显然和person2就没有关系了。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">第三条虽然也是在setTimeout的回调中，但是我们可以看出，这是执行的是person2.sayHi()使用的是隐式绑定，因此这是this指向的是person2，跟当前的作用域没有任何关系。</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>

<p>显示绑定：即通过call、apply、bind的方式，显式地指定this所指向的对象。</p>
<p>new绑定：在js中，构造函数只是使用new操作符时被调用的函数，其实跟普通函数没有区别。任何一个函数都可以使用new调用，只有对于函数的构造调用。我们在使用new调用函数时，就会将新对象绑定在这个函数的this上。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayHi</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = name;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> Hi = <span class="keyword">new</span> sayHi(<span class="string">'Yevtte'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'Hello,'</span>, Hi.name);</span><br></pre></td></tr></table></figure>

<p>箭头函数：箭头函数它和普通函数有一些区别，箭头函数没有自己的this，它的this继承于外层代码库中的this。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">    hi: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="params">()</span>=&gt;</span>&#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="keyword">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    sayHi: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="keyword">this</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="function"><span class="params">()</span>=&gt;</span>&#123;</span><br><span class="line">                <span class="built_in">console</span>.log(<span class="keyword">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    say: <span class="function"><span class="params">()</span>=&gt;</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> hi = obj.hi();  <span class="comment">//输出obj对象，隐式绑定规则</span></span><br><span class="line">hi();               <span class="comment">//输出obj对象，执行的是箭头函数，因为箭头函数会往上级寻找this指向</span></span><br><span class="line"><span class="keyword">let</span> sayHi = obj.sayHi();</span><br><span class="line"><span class="keyword">let</span> fun1 = sayHi(); <span class="comment">//输出window；此时执行sayhi，会有隐式绑定的丢失，因为你实际上是在全局作用域执行的</span></span><br><span class="line">fun1();             <span class="comment">//输出window；执行箭头函数，指向外层代码</span></span><br><span class="line">obj.say();          <span class="comment">//输出window；执行箭头函数，往上找一层为window</span></span><br><span class="line"><span class="comment">//箭头函数的this不是静态的，始终继承于外层代码库中的this.</span></span><br></pre></td></tr></table></figure>

<p>如何准确地判断this指向的是什么？</p>
<ol>
<li>函数是否在new中调用(new绑定)，如果是，那么this绑定的是新创建的对象。</li>
<li>函数是否通过call,apply调用，或者使用了bind(即硬绑定)，如果是，那么this绑定的就是指定的对象。</li>
<li>函数是否在某个上下文对象中调用(隐式绑定)，如果是的话，this绑定的是那个上下文对象。一般是obj.foo()</li>
<li>如果以上都不是，那么使用默认绑定。如果在严格模式下，则绑定到undefined，否则绑定到全局对象。</li>
<li>如果把null或者undefined作为this的绑定对象传入call、apply或者bind，这些值在调用时会被忽略，实际应用的是默认绑定规则。</li>
<li>如果是箭头函数，箭头函数的this继承的是外层代码块的this。</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1、不管多少层调用，指向调用时的上一层对象。</span></span><br><span class="line"><span class="keyword">var</span> flora = &#123;</span><br><span class="line">    Animal:<span class="string">"a"</span>,</span><br><span class="line">    mars:&#123;</span><br><span class="line">        Animal:<span class="string">"b"</span>,</span><br><span class="line">        say:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123; </span><br><span class="line">            <span class="built_in">console</span>.log(<span class="keyword">this</span>.Animal);</span><br><span class="line">    	&#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line">flora.mars.say();<span class="comment">//输出为b</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//2、定义时不决定this，指向调用时的对象</span></span><br><span class="line"><span class="keyword">var</span> flora = &#123;</span><br><span class="line">    Animal:<span class="string">"a"</span>,</span><br><span class="line">    mars:&#123;</span><br><span class="line">        Animal:<span class="string">"b"</span>,</span><br><span class="line">        say:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123; </span><br><span class="line">            <span class="built_in">console</span>.log(<span class="keyword">this</span>);</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="keyword">this</span>.Animal);</span><br><span class="line">    	&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> pink = flora.mars.say;</span><br><span class="line">pink();<span class="comment">//输出分别为window和undefine，因为pink()在全局环境上调用，因此this为window。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//3、new会改变this的指向</span></span><br><span class="line"><span class="comment">/*但当构造函数有返回值时，又不一样了，</span></span><br><span class="line"><span class="comment">如果返回的是一个对象：this会指向哪个返回的对象。</span></span><br><span class="line"><span class="comment">如果返回的不是一个对象：this还是指向那个函数的实例 */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">flora</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.animal = <span class="string">"a"</span>;   </span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> blue = <span class="keyword">new</span> flora();</span><br><span class="line"><span class="built_in">console</span>.log(blue.animal); <span class="comment">//a</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">flora</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.animal = <span class="string">"a"</span>;   </span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> blue = <span class="keyword">new</span> flora();</span><br><span class="line"><span class="built_in">console</span>.log(blue.animal); <span class="comment">//undefined</span></span><br></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> number = <span class="number">5</span>;</span><br><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">    number: <span class="number">3</span>,</span><br><span class="line">    fn: (<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> number;</span><br><span class="line">        <span class="keyword">this</span>.number *= <span class="number">2</span>;</span><br><span class="line">        number = number * <span class="number">2</span>;</span><br><span class="line">        number = <span class="number">3</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="keyword">var</span> num = <span class="keyword">this</span>.number;</span><br><span class="line">            <span class="keyword">this</span>.number *= <span class="number">2</span>;</span><br><span class="line">            <span class="built_in">console</span>.log(num);</span><br><span class="line">            number *= <span class="number">3</span>;</span><br><span class="line">            <span class="built_in">console</span>.log(number);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> myFun = obj.fn;</span><br><span class="line">myFun.call(<span class="literal">null</span>);</span><br><span class="line">obj.fn();</span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">window</span>.number);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">我们来分析一下，这段代码的执行过程。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">在定义obj的时候，fn对应的闭包就执行了，返回其中的函数，执行闭包中代码时，显然应用不了new绑定(没有出现new 关键字)，硬绑定也没有(没有出现call,apply,bind关键字),隐式绑定有没有？很显然没有，如果没有XX.fn()，那么可以肯定没有应用隐式绑定，所以这里应用的就是默认绑定了，非严格模式下this绑定到了window上(浏览器执行环境)。【这里很容易被迷惑的就是以为this指向的是obj，一定要注意，除非是箭头函数，否则this跟词法作用域是两回事，一定要牢记在心】</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">window</span>.number * = <span class="number">2</span>; <span class="comment">//window.number的值是10(var number定义的全局变量是挂在window上的)</span></span><br><span class="line">number = number * <span class="number">2</span>; <span class="comment">//number的值是NaN;注意我们这边定义了一个number，但是没有赋值，number的值是undefined;Number(undefined)-&gt;NaN</span></span><br><span class="line">number = <span class="number">3</span>;          <span class="comment">//number的值为3</span></span><br><span class="line"><span class="comment">//myFun.call(null);我们前面说了，call的第一个参数传null，调用的是默认绑定;</span></span><br><span class="line">fn: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">var</span> num = <span class="keyword">this</span>.number;</span><br><span class="line">    <span class="keyword">this</span>.number *= <span class="number">2</span>;</span><br><span class="line">    <span class="built_in">console</span>.log(num);</span><br><span class="line">    number *= <span class="number">3</span>;</span><br><span class="line">    <span class="built_in">console</span>.log(number);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//执行时:</span></span><br><span class="line"><span class="keyword">var</span> num = <span class="keyword">this</span>.number; <span class="comment">//num=10; 此时this指向的是window</span></span><br><span class="line"><span class="keyword">this</span>.number * = <span class="number">2</span>;     <span class="comment">//window.number = 20</span></span><br><span class="line"><span class="built_in">console</span>.log(num);      <span class="comment">//输出结果为10</span></span><br><span class="line">number *= <span class="number">3</span>;           <span class="comment">//number=9; 这个number对应的闭包中的number;闭包中的number的是3</span></span><br><span class="line"><span class="built_in">console</span>.log(number);   <span class="comment">//输出的结果是9</span></span><br><span class="line"><span class="comment">//obj.fn();应用了隐式绑定，fn中的this对应的是obj.</span></span><br><span class="line"><span class="keyword">var</span> num = <span class="keyword">this</span>.number;<span class="comment">//num = 3;此时this指向的是obj</span></span><br><span class="line"><span class="keyword">this</span>.number *= <span class="number">2</span>;     <span class="comment">//obj.number = 6;</span></span><br><span class="line"><span class="built_in">console</span>.log(num);     <span class="comment">//输出结果为3;</span></span><br><span class="line">number *= <span class="number">3</span>;          <span class="comment">//number=27;这个number对应的闭包中的number;闭包中的number的此时是9</span></span><br><span class="line"><span class="built_in">console</span>.log(number);  <span class="comment">//输出的结果是27</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*最后一步console.log(window.number);输出的结果是20</span></span><br><span class="line"><span class="comment">因此组中结果为:</span></span><br><span class="line"><span class="comment">10</span></span><br><span class="line"><span class="comment">9</span></span><br><span class="line"><span class="comment">3</span></span><br><span class="line"><span class="comment">27</span></span><br><span class="line"><span class="comment">20</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>



<h2 id="8、手写继承实现"><a href="#8、手写继承实现" class="headerlink" title="8、手写继承实现"></a>8、手写继承实现</h2><p><strong>使用原型链继承，继承了父类的属性和方法，但对于引用属性，由于传入的是其地址，因此多个指向的是同样的父类属性；使用构造函数来实现属性的继承，在子类中调用父类构造函数，从而现实例属性的继承，因此同样子类实例上的属性覆盖了父类的同名属性。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">(1)、借助call来实现继承(构造函数继承)</span></span><br><span class="line"><span class="comment">这样写的时候子类虽然能够拿到父类的属性值，但是问题是父类原型对象中一旦存在方法那么子类无法继承。</span></span><br><span class="line"><span class="comment">通过使用call()或apply()方法，Parent构造函数在为Child的实例创建的新对象的上下文执行了，</span></span><br><span class="line"><span class="comment">就相当于新的Child实例对象上运行了Parent()函数中的所有初始化代码，结果就是每个实例都有自己的info属性。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent1</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = <span class="string">'parent1'</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">Child1</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    Parent1.call(<span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">this</span>.type = <span class="string">'child1'</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="keyword">new</span> Child1);</span><br><span class="line"><span class="comment">/*(2)、原型链实现继承</span></span><br><span class="line"><span class="comment">将父类的实例作为子类的原型：父类的所有引用属性（info）会被所有子类共享，更改一个子类的引用属性，其他子类也会受影响</span></span><br><span class="line"><span class="comment">如下：两个child实例用的是一个原型对象，修改其中之一的play，会影响另一个的。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent2</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = <span class="string">'parent2'</span>;</span><br><span class="line">    <span class="keyword">this</span>.play = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">Child2</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.type = <span class="string">'child2'</span>;</span><br><span class="line">  &#125;</span><br><span class="line">Child2.prototype = <span class="keyword">new</span> Parent2();</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> Child2());</span><br><span class="line"><span class="comment">/*(3)、组合继承：同时应用上面两种继承方法</span></span><br><span class="line"><span class="comment">使用原型链继承原型上的属性和方法，而通过构造函数继承实例属性，这样既可以把方法定义在原型上以实现重用，又可以让每个实例都有自己的属性 */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent3</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = <span class="string">'parent3'</span>;</span><br><span class="line">    <span class="keyword">this</span>.play = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">  &#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Child3</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    Parent3.call(<span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">this</span>.type = <span class="string">'child3'</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  Child3.prototype = <span class="keyword">new</span> Parent3();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> s3 = <span class="keyword">new</span> Child3();</span><br><span class="line">  <span class="keyword">var</span> s4 = <span class="keyword">new</span> Child3();</span><br><span class="line">  s3.play.push(<span class="number">4</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(s3.play, s4.play);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*(4)、寄生组合继承</span></span><br><span class="line"><span class="comment">上面的组合继承有2点需要简单优化，1、避免parent构造函数执行2次；2、子类的构造函数应该指向Child，而不是Parent */</span></span><br><span class="line"><span class="comment">//new创建一个对象，执行构造函数。Object.create相当于创建一个对象，但是不执行构造函数。</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent5</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = <span class="string">'parent5'</span>;</span><br><span class="line">    <span class="keyword">this</span>.play = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">Child5</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    Parent5.call(<span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">this</span>.type = <span class="string">'child5'</span>;</span><br><span class="line">  &#125;</span><br><span class="line">Child5.prototype = <span class="built_in">Object</span>.create(Parent5.prototype);</span><br><span class="line">Child5.prototype.constructor = Child5;</span><br></pre></td></tr></table></figure>

<h2 id="11、手写防抖与节流"><a href="#11、手写防抖与节流" class="headerlink" title="11、手写防抖与节流"></a>11、手写防抖与节流</h2><p><strong>防抖：即短时间内大量触发同一事件，只会执行一次函数。原理：设置一个定时器，约定在xx毫秒之后再触发事件处理器，每次·触发事件都会重新设置处理器，直至xx毫秒内无第二次操作</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">debounce</span> (<span class="params">func, await</span>) </span>&#123;</span><br><span class="line">    <span class="comment">//传入参数分别为需要添加防抖的事件函数，和防抖的时间间隔</span></span><br><span class="line">    <span class="keyword">let</span> timeout = &#123;&#125;;</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">let</span> context = <span class="keyword">this</span>;</span><br><span class="line">        <span class="keyword">let</span> args = <span class="built_in">arguments</span>;</span><br><span class="line">        <span class="keyword">if</span> (timeout) clearTimeout(timeout);<span class="comment">//每次触发都会重置定时器</span></span><br><span class="line">        timeout = setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            func.apply(context, args);</span><br><span class="line">        &#125;, <span class="keyword">await</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>节流：间隔执行，每隔一段时间就执行一次。原理：设置一个定时器，约定xx毫秒后执行时间，如果时间到了，那么执行函数并重置定时器，和防抖的区别是：防抖每次触发事件都重置定时器，而节流在定时器到事件后再清空。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">throttle</span>(<span class="params">func, wait</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> timeout = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">let</span> context = <span class="keyword">this</span>;</span><br><span class="line">        <span class="keyword">let</span> args = <span class="built_in">arguments</span>;</span><br><span class="line">        <span class="keyword">if</span> (!timeout) &#123;</span><br><span class="line">            timeout = setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">                timeout = <span class="literal">null</span>;</span><br><span class="line">                func.apply(context, args);</span><br><span class="line">            &#125;, wait);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="12、Array-sort"><a href="#12、Array-sort" class="headerlink" title="12、Array.sort()"></a>12、Array.sort()</h2><p>默认情况下，sort()方法按升序排列数组项；且会调用每个数组项的toString()方法，比较字符串；因此直接用于数字比较不会正确。sort()可以接受一个函数作为参数，该函数可以接收两个参数，1、第一个参数应该位于第二个之前，则返回负数；</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> values = [<span class="number">0</span>, <span class="number">1</span>, <span class="number">5</span>, <span class="number">10</span>, <span class="number">15</span>];</span><br><span class="line">values.sort();</span><br><span class="line">alert(values);<span class="comment">//0, 1, 10 ,15 ,5 字符串比较时，10在5的前面，因此数组顺序被改变</span></span><br><span class="line">values.sort(<span class="function"><span class="keyword">function</span> <span class="title">compare</span> (<span class="params">value1, value2</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> value1 - value2;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">//当value1小于value2时，返回负数，小的放在前面，因此为升序排列。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*这里的话，我们顺便再手写一个快速排序吧</span></span><br><span class="line"><span class="comment">直接写一个较优的写法，主要分两步，</span></span><br><span class="line"><span class="comment">一个partition函数用于递归处理partition过程，传入参数为array，以及递归处理过程的左右index</span></span><br><span class="line"><span class="comment">一个quicksort用于调用partition进行快排实现，以及一些边界的特殊情况处理</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">var</span> quickSort_New = <span class="function"><span class="keyword">function</span>(<span class="params">ary, left, right</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(left &gt;= right) &#123;</span><br><span class="line">            <span class="keyword">return</span> ary;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> i = left,</span><br><span class="line">        <span class="keyword">var</span> j = right;</span><br><span class="line">        <span class="keyword">var</span> base = ary[left];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (i &lt; j) &#123;</span><br><span class="line">            <span class="comment">// 从右边起，寻找比基数小的数</span></span><br><span class="line">            <span class="keyword">while</span> (i&lt;j &amp;&amp; ary[j] &gt;= base) &#123;</span><br><span class="line">                j--;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 从左边起，寻找比基数大的数</span></span><br><span class="line">            <span class="keyword">while</span> (i&lt;j &amp;&amp; ary[i] &lt;= base) &#123;</span><br><span class="line">                i++</span><br><span class="line">            &#125; </span><br><span class="line">            <span class="keyword">if</span> (i &lt; j) &#123;</span><br><span class="line">                <span class="keyword">var</span> temp = ary[i];</span><br><span class="line">                ary[i] = ary[j];</span><br><span class="line">                ary[j] = temp;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        ary[left] = ary[i];</span><br><span class="line">        ary[i] = base;</span><br><span class="line">    	<span class="comment">//最后将base放至合适的位置</span></span><br><span class="line"></span><br><span class="line">        quickSort_New(ary, left, i<span class="number">-1</span>);</span><br><span class="line">        quickSort_New(ary, i+<span class="number">1</span>, right);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ary;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//或者有下面这种实现方式</span></span><br><span class="line"><span class="keyword">var</span> devide_Xin = <span class="function"><span class="keyword">function</span> (<span class="params">array, start, end</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(start &gt;= end) <span class="keyword">return</span> array;</span><br><span class="line">        <span class="keyword">var</span> baseIndex = <span class="built_in">Math</span>.floor((start + end) / <span class="number">2</span>), <span class="comment">// 基数索引</span></span><br><span class="line">             i = start,</span><br><span class="line">             j = end;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (i &lt;= j) &#123;</span><br><span class="line">            <span class="keyword">while</span> (array[i] &lt; array[baseIndex]) &#123;</span><br><span class="line">                i++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">while</span> (array[j] &gt; array[baseIndex])  &#123;</span><br><span class="line">                j--;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span>(i &lt;= j) &#123;</span><br><span class="line">                <span class="keyword">var</span> temp = array[i];</span><br><span class="line">                array[i] = array[j];</span><br><span class="line">                array[j] = temp;</span><br><span class="line">                i++;</span><br><span class="line">                j--;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> quickSort_Xin = <span class="function"><span class="keyword">function</span> (<span class="params">array, start, end</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(array.length &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> array;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> index = devide_Xin(array, start, end);</span><br><span class="line">        <span class="keyword">if</span>(start &lt; index <span class="number">-1</span>) &#123;</span><br><span class="line">            quickSort_Xin(array, start, index - <span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(end &gt; index) &#123;</span><br><span class="line">            quickSort_Xin(array, index, end);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> array;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>原理思路：基本上使用的是快速排序的方法。设要排序的元素个数是n：1、当 n &lt;= 10 时，采用插入排序；2、当 n &gt; 10 时，采用三路快速排序；3、10 &lt; n &lt;= 1000, 采用中位数作为哨兵元素；4、n &gt; 1000, 每隔 200~215 个元素挑出一个元素，放到一个新数组，然后对它排序，找到中间位置的数，以此作为中位数。</p>
<p>为什么要花这么大的力气选择哨兵元素？因为快速排序的性能瓶颈在于递归的深度，最坏的情况是每次的哨兵都是最小元素或者最大元素，那么进行partition(一边是小于哨兵的元素，另一边是大于哨兵的元素)时，就会有一边是空的，那么这么排下去，递归的层数就达到了n, 而每一层的复杂度是O(n)，因此快排这时候会退化成O(n^2)级别。</p>
<h2 id="13、手写Ajax请求"><a href="#13、手写Ajax请求" class="headerlink" title="13、手写Ajax请求"></a>13、手写Ajax请求</h2><p><strong>我们常用的 ajax 就是通过 XMLHttpRequest 对象实现的，这个对象有很多的属性和事件，在使用之前，我们需要先将它实例化.实例化后，我们就可以通过 xhr 来发起一个请求。</strong></p>
<p>xhr 具有一个 open 方法，这个方法的作用类似于初始化，并不会发起真正的请求；open 方法具有 5 个参数，但是常用的是前 3 个method： 请求方式 —— get / post；url：请求的地址；async：是否异步请求，默认为 true（异步）。send 方法发送请求，并接受一个可选参数，当请求方式为 post 时，可以将请求体的参数传入，当请求方式为 get 时，可以不传或传入 null，不管是 get 还是 post，参数都需要通过 encodeURIComponent 编码后拼接。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">ajax</span>(<span class="params">url, fnSucc, fnFaild</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> xhttp;</span><br><span class="line">    <span class="comment">// 第一步：创建XMLHttpRequest对象</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">window</span>.XMLHttpRequest) &#123;</span><br><span class="line">        <span class="comment">// 现代浏览器</span></span><br><span class="line">        xhttp = <span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line">     &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// IE6等老版本浏览器</span></span><br><span class="line">        xhttp = <span class="keyword">new</span> ActiveXObject(<span class="string">"Microsoft.XMLHTTP"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 第二步：调用XMLHttpRequest的open函数  </span></span><br><span class="line">    xhttp.open(<span class="string">'GET'</span>, url);</span><br><span class="line">    <span class="comment">// 第三步：XMLHttpRequest向服务器发送请求</span></span><br><span class="line">    xhttp.send();</span><br><span class="line">    <span class="comment">// 第四步：处理响应</span></span><br><span class="line">    xhttp.onreadystatechange = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"><span class="comment">//XMLHttpRequest上有一个方法，名叫onreadystatechange，当请求接收到响应的时候便会触发，在这个方法内部，我们来定义对响应的处理：</span></span><br><span class="line">      <span class="keyword">if</span> (xhttp.readyState === <span class="number">4</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (xhttp.status === <span class="number">200</span>) &#123;</span><br><span class="line">          fnSucc(xhttp.responseText)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (fnFaild) fnFaild(xhttp.responseText);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="14、手写发布订阅模式"><a href="#14、手写发布订阅模式" class="headerlink" title="14、手写发布订阅模式"></a>14、手写发布订阅模式</h2><p>发布订阅模式：又是观察者模式，定义对象的一对多的依赖关系，当一个对象的依赖发生改变时，所有依赖于它的对象都将得到通知。</p>
<p>一般我们会用传统的事件模型来代替发布订阅，事件的模式其实就是发布订阅模式。</p>
<p>发布订阅模式与观察者模式的不同，“第三者” （事件中心）出现。目标对象并不直接通知观察者，而是通过事件中心来派发通知。</p>
<p>基于一个事件（主题）通道，希望接收通知的对象 Subscriber 通过自定义事件订阅主题，被激活事件的对象 Publisher 通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//先定义一个观察者observer，用于将两个对象间的关系解耦，</span></span><br><span class="line"><span class="keyword">let</span> observer = &#123;</span><br><span class="line">    <span class="comment">//定义收集订阅的集合</span></span><br><span class="line">    subscribes: &#123;&#125;,</span><br><span class="line">    <span class="comment">//定义订阅事件,参数两个，第一个为订阅的类型，第二个为触发该订阅后执行的回调函数.</span></span><br><span class="line">    subscribe: <span class="function"><span class="keyword">function</span> (<span class="params">person, fn</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="keyword">this</span>.subscribes[type]) &#123;</span><br><span class="line">            <span class="comment">//当对于该事件，还没有订阅任何触发的回调函数时，则新建数组来存储</span></span><br><span class="line">            <span class="comment">//这样，针对不同的订阅者，事件触发时可触发不同回调，产生不同结果</span></span><br><span class="line">            <span class="keyword">this</span>.subscribes[type] = [];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> fn === <span class="string">"function"</span>) &#123;</span><br><span class="line">            <span class="keyword">this</span>.subscribes[type].push(fn);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">//定义发布事件，挨个地处理调用，且处理不存在的调用，第一个参数为发布的事件</span></span><br><span class="line">    <span class="comment">//第二个参数为传给触发订阅后执行的回调函数的参数，会根据订阅的顺序来进行挨个触发</span></span><br><span class="line">    publish: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">let</span> type = [].shife.call(<span class="built_in">arguments</span>);</span><br><span class="line">        <span class="keyword">let</span> fns = <span class="keyword">this</span>.subscribes[type];</span><br><span class="line">        <span class="keyword">let</span> (!fns || fns.length) &#123;</span><br><span class="line">            <span class="keyword">return</span> ;</span><br><span class="line">            <span class="comment">//当没有相关的订阅，则直接return</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//挨个进行调用数组中保存的回调，参数为后续publish的传入参数</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; fns.length; i++) &#123;</span><br><span class="line">            fns[i].apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">//删除订阅</span></span><br><span class="line">    remove: <span class="function"><span class="keyword">function</span> (<span class="params">type, fn</span>) </span>&#123;</span><br><span class="line">        <span class="comment">//当传入为type为undefined时，设置为全部删除</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> type === <span class="string">'undefined'</span>) &#123;</span><br><span class="line">            <span class="keyword">this</span>.subscribes = [];</span><br><span class="line">            <span class="keyword">return</span> ;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> fns = <span class="keyword">this</span>.subscribes[type];</span><br><span class="line">        <span class="keyword">if</span> (!fns || !fns.length) &#123;</span><br><span class="line">            <span class="keyword">return</span> ;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//当传入为fn为undefined时，设置为单个type全部删除</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> fn === <span class="string">'undefined'</span>) &#123;</span><br><span class="line">            fns.length = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">return</span> ;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//挨个遍历，仅删除对应项</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; fns.length; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (fns[i] === fn) &#123;</span><br><span class="line">                fns.splice(i, <span class="number">1</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">jobListForA</span>(<span class="params">jobs</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'A'</span>, jobs);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">jobListForB</span>(<span class="params">jobs</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'B'</span>, jobs);</span><br><span class="line">&#125;</span><br><span class="line">observer.subscribe(<span class="string">'job'</span>, jobListForA);<span class="comment">//订阅了A的笔试成绩</span></span><br><span class="line">observer.subscribe(<span class="string">'job'</span>, jobListForB);<span class="comment">//订阅了B的笔试成绩</span></span><br><span class="line">observer.subscribe(<span class="string">'exanminationA'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">score</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(score);</span><br><span class="line">&#125;);<span class="comment">//A订阅了测试成绩</span></span><br><span class="line">observer.subscribe(<span class="string">'exanminationB'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">score</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(score);</span><br><span class="line">&#125;);<span class="comment">//B订阅了测试成绩</span></span><br><span class="line">observer.subscribe(<span class="string">'interviewA'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">result</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(result);</span><br><span class="line">&#125;);</span><br><span class="line">observer.publish(<span class="string">'examinationA'</span>, <span class="number">100</span>);</span><br><span class="line">observer.publish(<span class="string">'examinationB'</span>, <span class="number">80</span>);</span><br><span class="line">observer.publish(<span class="string">'job'</span>, [<span class="string">'前端'</span>, <span class="string">'后端'</span>, <span class="string">'测试'</span>]);<span class="comment">//输出A、B的岗位</span></span><br></pre></td></tr></table></figure>

<p>下面的观察者模式是发布订阅模式的简化版</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 目标者类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Subject</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>() &#123;</span><br><span class="line">    <span class="keyword">this</span>.observers = [];  <span class="comment">// 观察者列表</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 添加</span></span><br><span class="line">  add(observer) &#123;</span><br><span class="line">    <span class="keyword">this</span>.observers.push(observer);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 删除</span></span><br><span class="line">  remove(observer) &#123;</span><br><span class="line">    <span class="keyword">let</span> idx = <span class="keyword">this</span>.observers.findIndex(<span class="function"><span class="params">item</span> =&gt;</span> item === observer);</span><br><span class="line">    idx &gt; <span class="number">-1</span> &amp;&amp; <span class="keyword">this</span>.observers.splice(idx, <span class="number">1</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 通知</span></span><br><span class="line">  notify() &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> observer <span class="keyword">of</span> <span class="keyword">this</span>.observers) &#123;</span><br><span class="line">      observer.update();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 观察者类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Observer</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">    <span class="keyword">this</span>.name = name;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 目标对象更新时触发的回调</span></span><br><span class="line">  update() &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">`目标者通知我更新了，我是：<span class="subst">$&#123;<span class="keyword">this</span>.name&#125;</span>`</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 实例化目标者</span></span><br><span class="line"><span class="keyword">let</span> subject = <span class="keyword">new</span> Subject();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 实例化两个观察者</span></span><br><span class="line"><span class="keyword">let</span> obs1 = <span class="keyword">new</span> Observer(<span class="string">'前端开发者'</span>);</span><br><span class="line"><span class="keyword">let</span> obs2 = <span class="keyword">new</span> Observer(<span class="string">'后端开发者'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 向目标者添加观察者</span></span><br><span class="line">subject.add(obs1);</span><br><span class="line">subject.add(obs2);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 目标者通知更新</span></span><br><span class="line">subject.notify();  </span><br><span class="line"><span class="comment">// 输出：</span></span><br><span class="line"><span class="comment">// 目标者通知我更新了，我是前端开发者</span></span><br><span class="line"><span class="comment">// 目标者通知我更新了，我是后端开发者</span></span><br></pre></td></tr></table></figure>



<h2 id="15、手写堆排序"><a href="#15、手写堆排序" class="headerlink" title="15、手写堆排序"></a>15、手写堆排序</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">堆排序的写法</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">heapSort</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> heapSize = arr.length;</span><br><span class="line">  buildHeap(arr);<span class="comment">//构造一个所有节点都满足arr[parent[i]] &gt; arr[i]的堆结构数组，这样就把值最大的那个节点换到了根节点</span></span><br><span class="line">  <span class="keyword">while</span>(heapSize &gt; <span class="number">1</span>) &#123; <span class="comment">//*1</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//在当前树中，交换位于根节点的最大值和最后一个节点的值,这样就把最大值排在了最后一个节点，这样就排好了最大值</span></span><br><span class="line">    <span class="keyword">const</span> temp = arr[<span class="number">0</span>];</span><br><span class="line">    arr[<span class="number">0</span>]=arr[heapSize<span class="number">-1</span>];</span><br><span class="line">    arr[heapSize<span class="number">-1</span>] = temp;</span><br><span class="line"></span><br><span class="line">    heapSize--;<span class="comment">//当前树中最后一个节点已经排好了值，故后面就不用再考虑这个节点，故新的树的大小减一</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (heapSize&gt;<span class="number">1</span>) &#123;</span><br><span class="line">      heapify(arr, heapSize, <span class="number">0</span>);</span><br><span class="line">        <span class="comment">//上面的交换操作产生了新的根节点，新的根节点只是通过跟最后一个节点交换得到的值，故新的根节点不满足条件arr[parent[i]]&lt;arr[i]，所以要对根节点再次进行h</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description </span>构造一个所有节点都满足arr[parent[i]] &gt; arr[i]的堆结构数组</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param <span class="type">&#123;Array&#125;</span> </span>arr 待排序数组</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildHeap</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> heapSize = arr.length;</span><br><span class="line">  <span class="keyword">const</span> firstHeapifyIndex = <span class="built_in">Math</span>.floor(heapSize/<span class="number">2</span><span class="number">-1</span>);</span><br><span class="line">    <span class="comment">//从树的倒数第二层的最后一个有子节点的节点（对于满二叉树就是倒数第二层的最后一个节点）开始进行heapify处理。Math.floor(heapSize/2-1)就是这个最后一个有子节点的节点索引。</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i=firstHeapifyIndex; i &gt;= <span class="number">0</span>; i--) &#123;<span class="comment">//从0到firstHeapifyIndex都要进行heapify处理，才能把最大的那个节点换到根节点</span></span><br><span class="line">    heapify(arr, heapSize, i);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description </span>以数组arr的前heapSize个节点为树，对其中索引为i的节点向子节点进行替换，直到满足从i往下的子节点都有arr[parent[i]]&gt;=arr[i]</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param <span class="type">&#123;*&#125;</span> </span>arr TYPE Array  待排序的数组</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param <span class="type">&#123;*&#125;</span> </span>heapSize TYPE Number 待排序的数组中要作为当前树处理的从前往后数的节点个数，即待排序数组中前heapSize个点是要作为树来处理</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param <span class="type">&#123;*&#125;</span> </span>i TYPE Number arr数组中、heapSize长度的树中的当前要进行往子节点替换的节点的索引</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">heapify</span>(<span class="params">arr, heapSize, i</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> leftIndex = i * <span class="number">2</span> + <span class="number">1</span>;<span class="comment">//索引i的节点的左子节点索引</span></span><br><span class="line">  <span class="keyword">const</span> rightIndex = i * <span class="number">2</span> + <span class="number">2</span>;<span class="comment">//索引i的节点的右子节点索引</span></span><br><span class="line">  <span class="keyword">let</span> biggestValueIndex = i;</span><br><span class="line">  <span class="keyword">if</span> (leftIndex &lt; heapSize &amp;&amp; arr[leftIndex] &gt; arr[biggestValueIndex]) &#123;</span><br><span class="line">    <span class="comment">//节点的最大index为heapSize-1</span></span><br><span class="line">    <span class="comment">//注意：这两次比较要跟arr[biggestValueIndex]比较，不能跟arr[i]比较，因为biggestValueIndex是会在左右i之间更新的</span></span><br><span class="line">    biggestValueIndex = leftIndex; <span class="comment">//如果左子节点的值大于biggestValueIndex的值（此时就是根节点的值），那么更新biggestValueIndex为左子节点索引</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (rightIndex &lt; heapSize &amp;&amp; arr[rightIndex] &gt; arr[biggestValueIndex]) &#123;</span><br><span class="line">    biggestValueIndex = rightIndex;<span class="comment">//如果右子节点的值大于biggestValueIndex的值(此时可能是根节点的值，也可能是左子节点的值)，那么更新biggestValueIndex为右子节点索引</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (biggestValueIndex !== i) &#123; <span class="comment">//如果biggestValueIndex是左子节点索引或右子节点索引，那么交换根节点与biggestValueIndex节点的值</span></span><br><span class="line">    <span class="keyword">const</span> temp = arr[i];</span><br><span class="line">    arr[i] = arr[biggestValueIndex];</span><br><span class="line">    arr[biggestValueIndex] = temp;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//交换后，被交换的那个子节点（左子节点或右子节点）往下可能就不再满足[parent[i]]&gt;=arr[i]，所以要继续对biggestValueIndex进行heaify处理，即将biggestValueIndex可能需要和子节点进行值交换,直到树的这个分支到叶子节点都满足arr[parent[i]]&gt;=arr[i]</span></span><br><span class="line">    heapify(arr, heapSize, biggestValueIndex);<span class="comment">//要</span></span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


    </div>
    
    
    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
        <div class="reward-container">
  <div>坚持原创技术分享，您的支持将鼓励我继续创作！</div>
  <button onclick="var qr = document.getElementById('qr'); qr.style.display = (qr.style.display === 'none') ? 'block' : 'none';">
    打赏
  </button>
  <div id="qr" style="display: none;">
      
      <div style="display: inline-block;">
        <img src="/images/alipay.png" alt="Li Yudong 支付宝">
        <p>支付宝</p>
      </div>

  </div>
</div>

        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>Li Yudong
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="http://example.com/2021/08/15/%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93/JS%E6%89%8B%E5%86%99%E9%97%AE%E9%A2%98/" title="JS手写问题">http://example.com/2021/08/15/面试总结/JS手写问题/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

    
      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93/" rel="tag"># 面试总结</a>
          </div>
    
        

    
        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2021/07/25/vue%E6%BA%90%E7%A0%81/vue%E5%AE%98%E7%BD%91/" rel="prev" title="vue官方文档">
      <i class="fa fa-chevron-left"></i> vue官方文档
    </a></div>
      <div class="post-nav-item">
    <a href="/2021/08/15/%E5%AD%A6%E6%A0%A1%E9%A1%B9%E7%9B%AE%E5%BA%94%E7%94%A8/jest%E6%B5%8B%E8%AF%95/" rel="next" title="Jest测试（待整理）">
      Jest测试（待整理） <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#前言"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1、promise相关"><span class="nav-number">1.1.</span> <span class="nav-text">1、promise相关</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2、深拷贝、浅拷贝"><span class="nav-number">1.2.</span> <span class="nav-text">2、深拷贝、浅拷贝</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3、判断数据类型"><span class="nav-number">1.3.</span> <span class="nav-text">3、判断数据类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4、数组常见API"><span class="nav-number">1.4.</span> <span class="nav-text">4、数组常见API</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5、手写bind、call、apply"><span class="nav-number">1.5.</span> <span class="nav-text">5、手写bind、call、apply</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6、手写new"><span class="nav-number">1.6.</span> <span class="nav-text">6、手写new</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#7、正确判断this"><span class="nav-number">1.7.</span> <span class="nav-text">7、正确判断this</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#8、手写继承实现"><span class="nav-number">1.8.</span> <span class="nav-text">8、手写继承实现</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11、手写防抖与节流"><span class="nav-number">1.9.</span> <span class="nav-text">11、手写防抖与节流</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12、Array-sort"><span class="nav-number">1.10.</span> <span class="nav-text">12、Array.sort()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#13、手写Ajax请求"><span class="nav-number">1.11.</span> <span class="nav-text">13、手写Ajax请求</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14、手写发布订阅模式"><span class="nav-number">1.12.</span> <span class="nav-text">14、手写发布订阅模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15、手写堆排序"><span class="nav-number">1.13.</span> <span class="nav-text">15、手写堆排序</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Li Yudong"
      src="/images/author.jpg">
  <p class="site-author-name" itemprop="name">Li Yudong</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">95</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">14</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">18</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/tiarmor1" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;tiarmor1" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:1157019137@qq.com" title="E-Mail → mailto:1157019137@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 2020 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Li Yudong</span>
</div>

        








      </div>
    </footer>
  </div>

  
  
  <script color='0,0,0' opacity='0.5' zIndex='-1' count='150' src="/lib1/canvas-nest/canvas-nest.min.js"></script>
  <script src="/lib1/anime.min.js"></script>
  <script src="/lib1/velocity/velocity.min.js"></script>
  <script src="/lib1/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  

  
   <canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas> 
   <script type="text/javascript" src="//cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script> 
   <script type="text/javascript" src="/js/fireworks.js"></script>
  
</body>
</html>

